package com.mathdroid.gui.main.abilities;

import java.awt.Color;
import java.awt.Dimension;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Insets;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

import javax.swing.JButton;
import javax.swing.JCheckBox;
import javax.swing.JLabel;

import com.mathdroid.core.DroidStringWorker;
import com.mathdroid.gui.ImageLoader;
import com.mathdroid.gui.componentlist.AComponentListElement;
import com.mathdroid.gui.componentlist.Cell;
import com.mathdroid.model.Model;

/**
 * This cell shows information about an ability.
 */
public final class AbilityCell extends Cell {
	
	/**
	 * The component constraints.
	 */
	private final GridBagConstraints c = new GridBagConstraints();
	
	/**
	 * The name of the ability.
	 */
	private final JLabel name = new JLabel();
	
	/**
	 * If the ability is enabled.
	 */
	private final JCheckBox enabled = new JCheckBox();
	
	/**
	 * The icon of the ability.
	 */
	private final JLabel icon = new JLabel();
	
	/**
	 * The space between components.
	 */
	private static final int SPACING = 5;
	
	/**
	 * The weight of wide components.
	 */
	private static final int HEAVY_WEIGHT = 100;
	
	/**
	 * The length of up/down button edges.
	 */
	private static final int BUTTON_SIZE = 20;
	
	/**
	 * A button to increase priority.
	 */
	private final JButton up = new JButton();
	
	/**
	 * A button to lower priority.
	 */
	private final JButton down = new JButton();
	
	/**
	 * Image loader.
	 */
	private final ImageLoader il = new ImageLoader();

	/**
	 * Default UID.
	 */
	private static final long serialVersionUID = 1L;
	
	/**
	 * Swing worker.
	 */
	private final DroidStringWorker sw = new DroidStringWorker();
	
	/**
	 * The ability model element of this view.
	 */
	private AbilityElement a = null;
	
	/**
	 * The background color for unavailable abilities.
	 */
	private static final Color UNAVAILABLE_BG_COLOR = new Color(255, 230, 230);
	
	/**
	 * The background color for abilities that are not available for 
	 * optimization.
	 */
	private static final Color NO_OPTIMIZATION_BG_COLOR = 
		new Color(255, 255, 230);
	
	/**
	 * Create an ability cell.
	 * @param e The model of this cell.
	 */
	public AbilityCell(final AComponentListElement e) {
		super();
		this.a = (AbilityElement) e;
		this.setLayout(new GridBagLayout());
		this.buildComponents();
		
		if (!this.a.getAbility().isUsedForOptimization()) {
			this.setBackground(NO_OPTIMIZATION_BG_COLOR);
		} else if (!this.a.getAbility().isAvailabe()) {
			this.setBackground(UNAVAILABLE_BG_COLOR);
		}
	}

	/**
	 * Build the "down" button.
	 */
	private void buildDown() {
		this.c.fill = GridBagConstraints.NONE;
		this.c.insets = new Insets(SPACING, 0, SPACING, SPACING);
		this.c.gridx = 3;
		this.c.gridy = 1;
		this.c.weightx = 1;
		this.c.weighty = 0;
		this.c.gridwidth = 1;
		this.c.gridheight = 1;
		
		this.down.setPreferredSize(new Dimension(BUTTON_SIZE, BUTTON_SIZE));
		this.down.setIcon(this.il.getImage("arrow_down"));
		this.down.addActionListener(new ActionListener() {
			@Override
			public void actionPerformed(final ActionEvent e) {
				Model.getProfile().getAbilities().swap(
						a.getIndex(), a.getIndex() + 1);
			}
		});
		
		this.add(this.down, this.c);
	}

	/**
	 * Build the "up" button.
	 */
	private void buildUp() {
		this.c.fill = GridBagConstraints.NONE;
		this.c.insets = new Insets(SPACING, 0, SPACING, SPACING);
		this.c.gridx = 3;
		this.c.gridy = 0;
		this.c.weightx = 1;
		this.c.weighty = 0;
		this.c.gridwidth = 1;
		this.c.gridheight = 1;
		
		this.up.setPreferredSize(new Dimension(BUTTON_SIZE, BUTTON_SIZE));
		this.up.setIcon(this.il.getImage("arrow_up"));
		this.up.addActionListener(new ActionListener() {
			@Override
			public void actionPerformed(final ActionEvent e) {
				Model.getProfile().getAbilities().swap(
						a.getIndex(), a.getIndex() - 1);
			}
		});
		
		this.add(this.up, this.c);
	}

	/**
	 * Build the "name" text.
	 */
	private void buildName() {
		this.c.fill = GridBagConstraints.NONE;
		this.c.insets = new Insets(SPACING, 0, SPACING, SPACING);
		this.c.gridx = 2;
		this.c.gridy = 0;
		this.c.weightx = HEAVY_WEIGHT;
		this.c.weighty = 0;
		this.c.gridwidth = 1;
		this.c.gridheight = 2;
		
		if (!this.a.getAbility().isAvailabe()
				|| !this.a.getAbility().isUsedForOptimization()) {
			this.name.setForeground(Color.GRAY);
		}
		this.name.setFont(this.name.getFont().deriveFont(15f));
		this.name.setText(this.a.getAbility().getName());
		this.name.setToolTipText(this.getToolTipText());
		
		this.add(this.name, this.c);
	}

	/**
	 * Build the "enabled" check box.
	 */
	private void buildCheckBox() {
		this.c.fill = GridBagConstraints.NONE;
		this.c.insets = new Insets(SPACING, 0, SPACING, SPACING);
		this.c.gridx = 1;
		this.c.gridy = 0;
		this.c.weightx = 1;
		this.c.weighty = 0;
		this.c.gridwidth = 1;
		this.c.gridheight = 2;
		
		if (!this.a.getAbility().isUsedForOptimization()) {
			this.enabled.setBackground(NO_OPTIMIZATION_BG_COLOR);
			this.enabled.setEnabled(false);
		} else if (!this.a.getAbility().isAvailabe()) {
			this.enabled.setBackground(UNAVAILABLE_BG_COLOR);
			this.enabled.setEnabled(false);
		}
		this.enabled.setSelected(this.a.getAbility().isEnabled());
		this.enabled.setToolTipText(
				"Enable or disable the use of this ability completely.");
		
		this.enabled.addActionListener(new ActionListener() {
			@Override
			public void actionPerformed(final ActionEvent e) {
				if (enabled.isSelected()) {
					a.getAbility().setEnabled(true);
				} else {
					a.getAbility().setEnabled(false);
				}
			}
		});
		
		this.add(this.enabled, this.c);
	}

	/**
	 * Build the ability icon.
	 */
	private void buildIcon() {
		this.c.fill = GridBagConstraints.NONE;
		this.c.insets = new Insets(SPACING, SPACING, SPACING, SPACING);
		this.c.gridx = 0;
		this.c.gridy = 0;
		this.c.weightx = 1;
		this.c.weighty = 0;
		this.c.gridwidth = 1;
		this.c.gridheight = 2;
		
		this.icon.setIcon(this.il.getAbilityIcon(
				this.a.getAbility().getIconName()));
		this.icon.setToolTipText(this.getToolTipText());
		
		this.add(this.icon, this.c);
	}
	
	/**
	 * Build the ToolTip HTML text.
	 * @return Description.
	 */
	public String getToolTipText() {
		String s = new String("<html>");
		
		s += "<b>" + this.a.getAbility().getName() + "</b><br>";
		
		if (this.a.getAbility().getCooldownMs() > 0d) {
			s += "<br><b>Cooldown:</b> " 
				+ this.a.getAbility().getCooldownMs() / 1000d 
				+ "s";
		}
		
		if (this.a.getAbility().getCastTimeMs() > 0d) {
			s += "<br><b>Casttime:</b> " 
				+ this.a.getAbility().getCastTimeMs() / 1000d 
				+ "s";
		}
		
		if (this.a.getAbility().getCost() > 0d) {
			s += "<br><b>" + this.a.getAbility().getResource() + " Cost:</b> " 
				+ (int) this.a.getAbility().getCost();
		}
		
		s += "<br><b>Trainable Level: </b>" 
			+ this.a.getAbility().getTrainableLevel() + "<br>";

		
		s += "<br>" + this.sw.insertBreaks(
				this.a.getAbility().getDescription()) + "<br>";
		
		if (!this.a.getAbility().isUsedForOptimization()) {
			s += "<br><font color=\"red\">This ability is not available "
					+ "for optimization.</font>";
		} else if (!this.a.getAbility().isAvailabe()) {
			s += "<br><font color=\"red\">You do not have the required "
					+ "skill.</font>";
		}
		
		return s + "</html>";
	}

	/**
	 * Add the components to this cell.
	 */
	public void buildComponents() {		
		this.buildIcon();
		this.buildCheckBox();
		this.buildName();
		
		if (this.a.getIndex() > 0) {
			this.buildUp();
		}
		
		if (this.a.getIndex() < Model.getProfile().getAbilities().size() - 1) {
			this.buildDown();
		}
	}
}
